/**
 * @author : niu niu
 * @version : 1.0.0
 * @date : 2022/8/28 22:51
 * 线程安全 ：　
 *          产生线程不安全的原因：
 *              1.线程之间是抢占式执行（根本原因） 抢占式执行，导致两个线程里面的操作的先后顺序无法确定，随机性
 *                  无力改变
 *              2.多个线程修改同一个变量，线程不安全 【变换代码组织形式】
 *                  一个线程修改，多个线程读取，多个线程修改不同的变量，不发生线程不安全
 *              3.原子性 非原子性操作导致线程不安全
 *                  通过加锁可以去除
 *              4.内存可见性 一个线程修改，一个修改，由于编译器优化，可能读到未修改的值
 *              5.指令重排序   编译器优化相关
 *          解决方法:
 *              从 原子性，内存可见性，指令重排序 入手解决
 *              synchronized 通过加锁的方式实现原子性，内存可见性
 *              对于指令重排序，有一定约束，但是不能禁止
 *
 *              volatile 不能保证原子性，但是可以保证内存可见性，禁止指令重排序
 *
 */
public class ThreadDemo15 {
    static class Counter{
        //每执行一次count，进行三个步骤：1.把内存的值读取到CPU中 LOAD
        //                             2.执行++操作 ADD
        //                             3.把CPU的值写回内存 SAVE
        //  线程按顺序 依次执行则不会出错，但是要是线程1的SAVE在 线程2的LOAD之后，则会出错，这就是：线程不安全
        //通过加锁         synchronized
        //锁的对象可以是任意对象  但是要是同一吧锁
        public int count = 0;
        public void increase(){
            count++;
        }
    }

    static Counter counter = new Counter();

    public static void main(String[] args) {
        Object locker = new Object();
        //创建两个线程，分别对count自增5w次
        Thread t1 = new Thread(){
            @Override
            public void run() {
                synchronized (locker){
                    for (int i = 0; i < 50000; i++) {
                        counter.increase();
                    }
                }
            }
        };

        Thread t2 = new Thread(){
            @Override
            public void run() {
                synchronized (locker){
                    for (int i = 0; i < 50000; i++) {
                        counter.increase();
                    }
                }
            }
        };

        t1.start();
        t2.start();

        try {
            t1.join(0);
            t2.join(0);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("counter = "+counter.count);


    }

}
